<?php

namespace Modules\Common\Models;

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Modules\Common\Exceptions\Base\Exception as CommonException;
use Modules\Common\Exceptions\Base\OutServiceFaultException;
use Modules\Common\Exceptions\Base\ServerFaultException;
use Modules\Common\Exceptions\Base\UserFaultException;
use Modules\Common\Exceptions\Common\TokenExpiredException;
use Modules\Common\Exceptions\Common\WrongVerifyCodeException;
use Modules\Common\General\Notification\SystemError\SystemErrorNofifyQueue;
use Modules\Common\General\Security\Api\Gateway;
use Modules\Common\General\Security\Authorization\Exceptions\AuthorizationMissingException;
use Modules\Common\Models\Validation\SystemErrorValidation;
use Modules\Common\Util\Database;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class SystemError extends BaseModel
{
    protected $connection = 'mysql';
    protected $table = 'system_errors';
    use SystemErrorValidation;

    protected static $shouldNotNotify = [
        NotFoundHttpException::class,
        TokenExpiredException::class,
        AuthorizationMissingException::class,
        WrongVerifyCodeException::class,

    ];


    public static function saveNew(\Throwable $exception, $type = 1)
    {
        try {
            self::doSaveNew($exception);
        } catch (\Throwable $e) {
            $message = $e instanceof CommonException ? $e->getUserMessage() : $e->getMessage();
            Log::error('创建异常记录失败', ['exceptionClassName' => (new \ReflectionClass($e))->getName(), 'message' => $message, 'trace' => $e->getTraceAsString()]);
        }
    }


    protected static function doSaveNew($exception)
    {
        $exceptionClassName = (new \ReflectionClass($exception))->getName();
        $title = $exception->getMessage() ? $exception->getMessage() : $exceptionClassName;

        if ($exception instanceof CommonException) {
            if ($exception instanceof UserFaultException) {
                $reasonType = 2;//2：用户类
            } elseif ($exception instanceof ServerFaultException) {
                $reasonType = 1;//1：系统类
            } elseif ($exception instanceof OutServiceFaultException) {
                $reasonType = 3;//3：第三方
            } else {
                $reasonType = 0;
            }

            $content = [
                'logMessage' => $exception->getDescription(),
                'context' => $exception->logContext(),
                'userMessage' => $exception->getUserMessage(),
                'exception' => $exceptionClassName,
                'request' => request()->all(),
                'trace' => $exception->getTrace(),

            ];

        } else {
            $reasonType = 5;//5：其他未捕获异常
            $content = [
                'exception' => $exceptionClassName,
                'request' => request()->all(),
                'trace' => $exception->getTrace(),

            ];
        }


        $content = json_encode($content, JSON_UNESCAPED_UNICODE);

        if (app()->runningInConsole()) {
            $clientIp = '127.0.0.1';
            $userAgent = '系统';
            $route = Database::STR_DEFAULT;
            $method = Database::STR_DEFAULT;
            $userId = Database::INT_DEFAULT;
            $userName = Database::STR_DEFAULT;
            $userMobile = '18000000000';


            $userType = 4;//4：系统

            if (Str::contains(implode(' ', $_SERVER['argv']), 'queue')) {
                $source = 5;//5：队列进程
            } elseif (Str::contains(implode(' ', $_SERVER['argv']), 'schedule')) {
                $source = 4;//4：定时任务
            } else {
                $source = 6;//6：命令行
            }
        } else {
            $clientIp = request()->getClientIp();
            $userAgent = request()->userAgent();
            $route = request()->path();
            $method = request()->method();
            if (request()->is('api/admin/*') && Gateway::user() instanceof AdminUser) {
                $user = Gateway::AdminUser();

                $userType = 3;//3：管理员
                $source = 3;//3：后台
                $userId = $user->id;
                $userName = $user->zh_name;
                $userMobile = $user->mobile;

            } elseif (request()->is('api/web/*') && Gateway::user() instanceof EnterpriseUser) {
                $user = Gateway::EnterpriseUser();
                $superEnterpriseUserAccount = SuperEnterpriseUserAccount::where('enterprise_user_id', $user->id)->first();
                $superEnterpriseUser = SuperEnterpriseUser::find($superEnterpriseUserAccount->super_enterprise_user_id);

                $userType = 2;//2：企业
                $source = 2;//2：企业端
                $userId = $user->id;
                $userName = $superEnterpriseUser->zh_name;
                $userMobile = $superEnterpriseUser->mobile;
            } elseif (request()->is('api/wechat/*') && Gateway::user() instanceof EmployeeUser) {
                $user = Gateway::EmployeeUser();
                $userType = 1;//1：个人
                $source = 1;//1：小程序
                $userId = $user->id;
                $userName = $user->employee->name ?: '-';
                $userMobile = $user->mobile;
            } else {
                $userType = 5;//5：游客
                $source = 7;//7：通用接口
                $userId = Database::INT_DEFAULT;
                $userName = '游客';//5：游客
                $userMobile = request('mobile', '18000000000');
            }
        }

        $data = [
            'title' => $title,
            'content' => $content,
            'type' => 1,//1:系统捕获
            'source' => $source,
            'status' => 1,//1：未通知
            'user_id' => $userId,
            'user_type' => $userType,
            'user_ip' => $clientIp,
            'user_agent' => mb_substr($userAgent, 0, 255),
            'user_name' => $userName,
            'user_mobile' => $userMobile,
            'route' => $route,
            'method' => $method,
            'reason_type' => $reasonType,//5：其他未捕获异常
        ];


        $error = SystemError::createFromArray($data);


        if (!config('app.debug') && !in_array($exceptionClassName, self::$shouldNotNotify)) {
            SystemErrorNofifyQueue::dispatch($error->id)->onConnection('database')->onQueue('system-error-mail-notify');
        }
    }


}